﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="AgentSession.cs" company="Data Ductus Malmö">
//   (c) 2010 - 2012 Data Ductus Malmö AB
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace DataDuctus.Snmp.Persistor.Core.Agent
{
  using System;
  using System.Collections.Generic;
  using System.Linq;

  using DataDuctus.Snmp.Persistor.Core.Agent.Internal;
  using DataDuctus.Snmp.Persistor.Core.MetaData;
  using DataDuctus.Snmp.Persistor.Core.Persistor;

  using Lextm.SharpSnmpLib;
  using Lextm.SharpSnmpLib.Messaging;
  using Lextm.SharpSnmpLib.Pipeline;

  /// <summary>
  /// The agent session.
  /// </summary>
  public class AgentSession : IDisposable
  {
    #region Fields

    /// <summary>
    /// The factory.
    /// </summary>
    private readonly EntityPersistorFactory factory;

    /// <summary>
    /// The store.
    /// </summary>
    private readonly ObjectStore store;

    /// <summary>
    /// The engine.
    /// </summary>
    private SnmpEngine engine;

    #endregion

    #region Constructors and Destructors

    /// <summary>
    /// Initializes a new instance of the <see cref="AgentSession"/> class.
    /// </summary>
    /// <param name="entityPersistorFactory">
    /// The entity persistor factory.
    /// </param>
    /// <param name="connection">
    /// The connection.
    /// </param>
    internal AgentSession(EntityPersistorFactory entityPersistorFactory, IEnumerable<ConnectionMeta> connection)
    {
      ConnectionMeta readConnection =
        (from conn in connection where conn.ConnectionType == ConnectionType.Read select conn).First();

      this.factory = entityPersistorFactory;
      this.store = new ObjectStore();

      this.engine =
        new SnmpEngine(
          new SnmpApplicationFactory(
            new ConsoleLogger(), 
            this.store, 
            new Version2MembershipProvider(
              new OctetString(readConnection.SecurityString), new OctetString(readConnection.SecurityString)), 
            new MessageHandlerFactory(
              new[]
                {
                  new HandlerMapping("v1", "GET", new GetV1MessageHandler()), 
                  new HandlerMapping("v2,v3", "GET23", new GetMessageHandler()), 
                  new HandlerMapping("*", "SET", new SetV1MessageHandler()), 
                  new HandlerMapping("v1", "GETNEXT", new GetNextV1MessageHandler()), 
                  new HandlerMapping("v2,v3", "GETNEXT23", new GetNextMessageHandler()), 
                  new HandlerMapping("v2,v3", "GETBULK", new GetBulkMessageHandler()), 
                  new HandlerMapping("*", "*", new DummyMessageHandler()) 
                })), 
          new Listener(), 
          new EngineGroup());
    }

    #endregion

    #region Public Methods and Operators

    /// <summary>
    /// The dispose.
    /// </summary>
    public void Dispose()
    {
      if (null != this.engine)
      {
        this.engine.Dispose();
      }

      this.engine = null;
    }

    /// <summary>
    /// The register entity.
    /// </summary>
    /// <param name="entity">
    /// The entity.
    /// </param>
    public void RegisterEntity(object entity)
    {
      ClassMeta clzMeta = this.factory.Config.Repository.Classes[entity.GetType()];

      foreach (AccessorMeta accessorMeta in clzMeta.Accessors)
      {
        if (accessorMeta.IsTable)
        {
          this.store.Add(new TableWrapper(clzMeta, accessorMeta, entity));
        }
        else
        {
          foreach (ScalarWrapper scalarWrapper in ScalarWrapper.CreateWrappers(clzMeta, entity))
          {
            this.store.Add(scalarWrapper);
          }
        }
      }
    }

    #endregion
  }
}